home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Magnum One
/
Magnum One (Mid-American Digital) (Disc Manufacturing).iso
/
d12
/
cgazv5n5.arc
/
LZW1.C
< prev
next >
Wrap
C/C++ Source or Header
|
1991-09-23
|
9KB
|
268 lines
/*--- LZW1.C ----------------------------- Listing 2 ------
* Contents: This is the compression portion of the
* LZW data compression program. It
* contains the following routines:
* compression_routine
* write_out_code
* wk_is_in_table
* put_wk_in_table
* build_string
* create_string
* append_char
* initialize
*
* Author: Dwayne Phillips
* Compiler: Microsoft C 6.0a, BC++ 2.0
* Note: Must link with at least an 8K stack
* Switches: DEBUG - if defined, debugging data is shown
* STATS - if defined, statistics are given
* Date: February 1991
* May be used freely if authorship is acknowledged
*--------------------------------------------------------*/
#include "lzw.h"
/*--------------------------------------------------------
* This is the main routine for the compression process.
*-------------------------------------------------------*/
void compression_routine( table_item *string_table,
FILE *infile, FILE *outfile )
{
unsigned char in_buffer[IB_LENGTH_C], w[100];
unsigned bytes_read;
unsigned in_counter, out_counter;
code_type out_buffer[OB_LENGTH_C], w_code;
unsigned table_max;
/* start up */
table_max = initialize ( string_table );
bytes_read = my_read ( infile, in_buffer,
sizeof(unsigned char), IB_LENGTH_C );
SHOW( printf( "\nIn: "); )
SHOW( printf ( isprint ( in_buffer[0]) ? "'%c'" : "%3dd",
in_buffer[0]); )
create_string ( w, in_buffer[0] );
w_code = in_buffer[0];
SHOW( { unsigned char *s; printf ( " w: '" ); )
SHOW( for ( s = w; *s; s++ )
printf( isprint ( *s ) ? "%c" : " %dd ", *s); )
SHOW( printf ( "'" ); } )
in_counter = 1;
out_counter = 0;
for(;;) {
for ( ; in_counter<bytes_read; in_counter++ ) {
int k;
code_type wk;
k = in_buffer[in_counter];
SHOW( printf("\nIn: "); )
SHOW( printf ( isprint(k) ? "'%c'" : "%3dd", k ); )
if ( k == '\0' || /* NULLs are special */
( wk = wk_is_in_table(w, k, string_table)) == 0) {
write_out_code( w_code, out_buffer,
&out_counter, outfile );
if ( k != '\0' && strlen ( w ) != 0 )
put_wk_in_table( w_code, k,
string_table, &table_max );
create_string( w, k );
w_code = k;
SHOW( { unsigned char *s; printf ( " w: '" ); )
SHOW( for (s = w; *s; s++) printf(isprint(*s) ?
"%c" : " %dd ", *s ); )
SHOW( printf ( "'" ); } )
}
/* wk is a known code, so note what we've found */
else {
append_char( w, k );
w_code = wk;
SHOW( { unsigned char *s; printf (" w: '"); )
SHOW( for ( s = w; *s; s++ )
printf( isprint(*s) ? "%c" : " %dd ", *s);)
SHOW( printf( "'" ); } )
}
}
/* get another block */
if ( feof ( infile ))
break;
bytes_read = my_read ( infile, in_buffer,
sizeof(unsigned char), IB_LENGTH_C );
in_counter = 0;
}
/* code last string and quit */
write_out_code( w_code, out_buffer,
&out_counter, outfile );
my_write ( outfile, out_buffer, sizeof ( code_type ),
out_counter );
SHOW( print_string_table ( string_table, "DONE",
BASE_TABLE + 1, table_max); )
#if defined(STATS)
printf ("Table had %d entries at conclusion.\n", table_max);
printf ("Input file was %ld bytes.\n", ftell ( infile ));
printf ("Output file is %ld bytes.\n", ftell ( outfile ));
#endif
} /* ends compression_routine */
/*--------------------------------------------------------
* Output a string's code to out_buffer. If the out_buffer
* is full, it writes the buffer to the output file.
*------------------------------------------------------*/
void write_out_code( code_type n,
code_type *out_buffer,
unsigned *out_counter,
FILE *outfile )
{
if( *out_counter >= OB_LENGTH_C ) {
my_write ( outfile, out_buffer,
sizeof ( code_type ), *out_counter );
*out_counter = 0;
}
SHOW( if (n <= BASE_TABLE && isprint(n)))
SHOW( printf(" Out: '%c'", n);
else printf(" Out: %3d", n);)
out_buffer[*out_counter] = n;
*out_counter += 1;
} /* ends write_out_code */
/*--------------------------------------------------------
* search the string table to see if the string w
* with the character k appended to it is present.
*
* find k
* build string w2 = w + k
* if w == w2 then return result = 1
* if not, find k again
* if you cannot find k where w2 == w
* then return result = 0
*------------------------------------------------------*/
code_type wk_is_in_table( unsigned char *w, int k,
table_item *string_table )
{
unsigned wlen;
code_type i;
wlen = strlen ( w );
/* as a special case, if w[] is empty, we never match */
if ( !wlen )
return 0;
/* walk the linked list of possible matches */
for ( i = string_table[k].chain; i != k;
i = string_table[i].chain ) {
code_type walk;
unsigned char *s;
unsigned count;
walk = string_table[i].num;
s = w + wlen - 1; /* end of string */
for ( count = wlen; count > 0; count -- ) {
if ( *s != (unsigned char)
string_table[walk].character )
break;
walk = string_table[walk].num;
s--;
}
if ( count == 0 && walk == 0 )
return (code_type) i;
}
return 0; /* if we get here, we didn't match */
}
/*--------------------------------------------------------
* insert the string w and character
* k into the string table.
*-------------------------------------------------------*/
void put_wk_in_table ( code_type w_code,
int k,
table_item *string_table,
unsigned *tmax )
{
/* watch for table overflow */
if ( *tmax == TABLE_SIZE - 1 )
return;
/* enter into next available slot */
*tmax += 1;
string_table[*tmax].num = w_code;
string_table[*tmax].character = k;
/* put self at head of linked list */
string_table[*tmax].chain = string_table[k].chain;
string_table[k].chain = *tmax;
SHOW( print_string_table(string_table,
"ADD", *tmax, *tmax); )
} /* ends put_wk_in_table */
/*--------------------------------------------------------
* take the number from the string table and use it
* to build a string w.
*------------------------------------------------------*/
void build_string( unsigned char *w, code_type number,
table_item *string_table )
{
int count;
code_type walk;
/* first, how long will the string be? */
for ( count=0, walk = number;
string_table[walk].character;
walk = string_table[walk].num )
count++;
/* now, build the string */
w[count--] = 0; /* terminator */
walk = number;
for ( ; count >= 0; count-- ) {
w[count] = (unsigned char) string_table[walk].character;
walk = string_table[walk].num;
}
}
/*--------------------------------------------------------
* take a character k and use it to create a
* 1 character long string w.
*------------------------------------------------------*/
void create_string ( unsigned char *w, int k )
{
w[0] = (unsigned char) k;
w[1] = '\0';
}
/*--------------------------------------------------------
* append the character k onto the
* end of the string w.
*------------------------------------------------------*/
void append_char ( unsigned char *w, int k )
{
unsigned i;
i = strlen ( w );
w[i] = (unsigned char) k;
w[i+1] = '\0';
} /* ends append_char */
/*--------------------------------------------------------
* initialize() sets the first 256 items in string_table
* to represent the corresponding ASCII codes. The remainder
* of the table is set to zero. The number of elements in
* the base table is returned as the function's value.
*------------------------------------------------------*/
unsigned initialize ( table_item *string_table )
{
int i;
for ( i = 0; i <= BASE_TABLE; i++ ){
string_table[i].num = 0;
string_table[i].chain = i;
string_table[i].character = i;
}
for( i = BASE_TABLE + 1; i < TABLE_SIZE; i++ ){
string_table[i].num = 0;
string_table[i].character = '\0';
}
return BASE_TABLE;
} /* ends initialize */